﻿//===================================================================================
// Copyright (c) Ryan Garrett.  All rights reserved.
// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY
// OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT
// LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
// FITNESS FOR A PARTICULAR PURPOSE.
//===================================================================================

using System;
using Caffeine.Core.Validation;

namespace Caffeine.Core
{
    /// <summary>
    /// Allows you to easily create validation method delegates for model properties
    /// </summary>
    public class ValidationHelper : IValidationHelper
    {
        public static readonly string ValueRequiredErrorMessage = "Value required";

        /// <summary>
        /// Creates a validation delegate for a ModelProperty&lt;String&gt; property
        /// </summary>
        /// <param name="nonDefaultValueRequired">True to require that a property always has a non-default value. This takes precedence over the <paramref name="ignoreCommitted"/> parameter.</param>
        /// <param name="ignoreCommitted">True to skip validation if the property is already committed, false to always validate the property</param>
        /// <param name="trimWhiteSpace">True to trim white space on either side of the value, false to not trim white space</param>
        /// <param name="minLength">The minimum number of characters allowed in the string property's value</param>
        /// <param name="maxLength">The maximum number of characters allowed in the string property's value</param>
        /// <param name="valueRequiredMessage">Message to display when a default value is assigned</param>
        /// <returns>A delegate for validating a property</returns>
        public PropertyValidationDel<String> CreateStringValidationMethod
        (
            Boolean nonDefaultValueRequired,
            Boolean ignoreCommitted, 
            Boolean trimWhiteSpace, 
            Int32 minLength, 
            Int32 maxLength
        )
        {
            return CreateStringValidationMethod(nonDefaultValueRequired, ignoreCommitted, trimWhiteSpace, minLength, maxLength, String.Empty, String.Empty, String.Empty, String.Empty, String.Empty);
        }

        /// <summary>
        /// Creates a validation delegate for a ModelProperty&lt;String&gt; property
        /// </summary>
        /// <param name="nonDefaultValueRequired">True to require that a property always has a non-default value. This takes precedence over the <paramref name="ignoreCommitted"/> parameter.</param>
        /// <param name="ignoreCommitted">True to skip validation if the property is already committed, false to always validate the property</param>
        /// <param name="trimWhiteSpace">True to trim white space on either side of the value, false to not trim white space</param>
        /// <param name="minLength">The minimum number of characters allowed in the string property's value</param>
        /// <param name="maxLength">The maximum number of characters allowed in the string property's value</param>
        /// <param name="valueRequiredMessage">Message to display when a default value is assigned</param>
        /// <param name="minLengthErrorFormatString">
        /// The validation error string to use if the string property value's length is less than the minimum 
        /// character length specified. String must contain exactly one parameter ({0}).
        /// </param>
        /// <param name="maxLengthErrorFormatString">
        /// The validation error string to use if the string property value's length is greater 
        /// than the maximum character length specified. String must contain exactly one parameter ({0}).
        /// </param>
        /// <param name="regularExpression">Regular expression used to validate property. If null or String.Empty is passed in this parameter will be ignored.</param>
        /// <param name="regularExpressionErrorString">Validation error string to use if the regular expression validation fails</param>
        /// <returns>A delegate for validating a property</returns>
        public PropertyValidationDel<String> CreateStringValidationMethod
        (
            Boolean nonDefaultValueRequired,
            Boolean ignoreCommitted,
            Boolean trimWhiteSpace,
            Int32 minLength,
            Int32 maxLength,
            String valueRequiredMessage,
            String regularExpression,
            String minLengthErrorFormatString,
            String maxLengthErrorFormatString,
            String regularExpressionErrorString
        )
        {
            return 
            (
                new StringValidationRule
                (
                    nonDefaultValueRequired, 
                    ignoreCommitted, 
                    trimWhiteSpace, 
                    minLength, 
                    maxLength,
                    valueRequiredMessage, 
                    regularExpression, 
                    minLengthErrorFormatString, 
                    maxLengthErrorFormatString,
                    regularExpressionErrorString
                )
            ).ValidationMethod;
        }

        /// <summary>
        /// Creates a validation delegate for ModelProperty&lt;T&gt; where T is a value type
        /// </summary>
        /// <typeparam name="T">Value type this delegate will validate</typeparam>
        /// <param name="nonDefaultValueRequired">True to require that a property always has a non-default value. This takes precedence over the <paramref name="ignoreCommitted"/> parameter.</param>
        /// <param name="ignoreCommitted">True to skip validation if the property is already committed, false to always validate the property</param>
        /// <param name="minValue">The minimum value allowed</param>
        /// <param name="maxValue">The maximum value allowed</param>
        /// <returns>A delegate for validating a property</returns>
        public PropertyValidationDel<T> CreateValueTypeValidationMethod<T>
        (
            Boolean nonDefaultValueRequired,
            Boolean ignoreCommitted, 
            T minValue, 
            T maxValue
        ) where T : struct
        {
            return CreateValueTypeValidationMethod<T>(nonDefaultValueRequired, ignoreCommitted, minValue, maxValue, String.Empty, String.Empty, String.Empty);
        }

        /// <summary>
        /// Creates a validation delegate for ModelProperty&lt;T&gt; where T is a value type
        /// </summary>
        /// <typeparam name="T">Value type this delegate will validate</typeparam>
        /// <param name="nonDefaultValueRequired">True to require that a property always has a non-default value. This takes precedence over the <paramref name="ignoreCommitted"/> parameter.</param>
        /// <param name="ignoreCommitted">True to skip validation if the property is already committed, false to always validate the property</param>
        /// <param name="minValue">The minimum value allowed</param>
        /// <param name="maxValue">The maximum value allowed</param>
        /// <param name="valueRequiredMessage">Message to display when a default value is assigned</param>
        /// <param name="minValueErrorFormatString">
        /// The validation error string to use if the model property's value is less than the minimum 
        /// value specified. String must contain exactly one parameter ({0}).
        /// </param>
        /// <param name="maxValueErrorFormatString">
        /// The validation error string to use if the model property's value is greater than the maximum 
        /// value specified. String must contain exactly one parameter ({0}).
        /// </param>
        /// <returns>A delegate for validating a property</returns>
        public PropertyValidationDel<T> CreateValueTypeValidationMethod<T>
        (
            Boolean nonDefaultValueRequired,
            Boolean ignoreCommitted,
            T minValue,
            T maxValue,
            String valueRequiredMessage,
            String minValueErrorFormatString,
            String maxValueErrorFormatString
        ) where T : struct
        {
            return (new ValueTypeValidationRule<T>(nonDefaultValueRequired, ignoreCommitted, minValue, maxValue, valueRequiredMessage, minValueErrorFormatString, maxValueErrorFormatString, false)).ValidationMethod;
        }

        /// <summary>
        /// Creates a validation delegate for ModelProperty&lt;T&gt; where T is a value type
        /// </summary>
        /// <typeparam name="T">Value type this delegate will validate</typeparam>
        /// <param name="nonDefaultValueRequired">True to require that a property always has a non-default value. This takes precedence over the <paramref name="ignoreCommitted"/> parameter.</param>
        /// <param name="ignoreCommitted">True to skip validation if the property is already committed, false to always validate the property</param>
        /// <param name="minValue">The minimum value allowed</param>
        /// <param name="maxValue">The maximum value allowed</param>
        /// <returns>A delegate for validating a property</returns>
        public PropertyValidationDel<Nullable<T>> CreateNullableValueTypeValidationMethod<T>
        (
            Boolean nonDefaultValueRequired,
            Boolean ignoreCommitted,
            T minValue,
            T maxValue
        ) where T : struct
        {
            return CreateNullableValueTypeValidationMethod<T>(nonDefaultValueRequired, ignoreCommitted, minValue, maxValue, String.Empty, String.Empty, String.Empty);
        }

        /// <summary>
        /// Creates a validation delegate for ModelProperty&lt;T&gt; where T is a value type
        /// </summary>
        /// <typeparam name="T">Value type this delegate will validate</typeparam>
        /// <param name="nonDefaultValueRequired">True to require that a property always has a non-default value. This takes precedence over the <paramref name="ignoreCommitted"/> parameter.</param>
        /// <param name="ignoreCommitted">True to skip validation if the property is already committed, false to always validate the property</param>
        /// <param name="minValue">The minimum value allowed</param>
        /// <param name="maxValue">The maximum value allowed</param>
        /// <param name="valueRequiredMessage">Message to display when a default value is assigned</param>
        /// <param name="minValueErrorFormatString">
        /// The validation error string to use if the model property's value is less than the minimum 
        /// value specified. String must contain exactly one parameter ({0}).
        /// </param>
        /// <param name="maxValueErrorFormatString">
        /// The validation error string to use if the model property's value is greater than the maximum 
        /// value specified. String must contain exactly one parameter ({0}).
        /// </param>
        /// <param name="nullErrorString">The validation error string to use if the value is null</param>
        /// <returns>A delegate for validating a property</returns>
        public PropertyValidationDel<Nullable<T>> CreateNullableValueTypeValidationMethod<T>
        (
            Boolean nonDefaultValueRequired,
            Boolean ignoreCommitted, 
            T minValue, 
            T maxValue,
            String valueRequiredMessage, 
            String minValueErrorFormatString,
            String maxValueErrorFormatString
        ) where T : struct
        {
            return (new NullableValueTypeValidationRule<T>(nonDefaultValueRequired, ignoreCommitted, minValue, maxValue, valueRequiredMessage, minValueErrorFormatString, maxValueErrorFormatString)).ValidationMethod;
        }
    }
}
